package atom.core0.jdbc;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

public class ORMUtil
{
	protected static final Logger	logger	= Logger.getLogger(ORMUtil.class);

	public static Object converttoModel(ResultSet rs, Class clazz)
	{
		Object obj = null;
		try
		{
			obj = clazz.newInstance();
		}
		catch (InstantiationException e1)
		{
			e1.printStackTrace();
		}
		catch (IllegalAccessException e1)
		{
			e1.printStackTrace();
		}
		Method[] methods = clazz.getDeclaredMethods();
		Field[] fields = clazz.getDeclaredFields();

		for (Field field : fields)
		{
			String fieldType = field.getType().getName();
			String fieldName = field.getName();
			String firstUpper = getBeanFieldName(fieldName);
			for (Method method : methods)
			{
				// 判断当前方法是否是set方法,并且当前的属性值在set之后
				if (method.getName().startsWith("set") && method.getName().indexOf(firstUpper) == 3)
				{
					// 对不同属性类型的属性进行，对应的赋值
					try
					{
						if (fieldType.equals("java.lang.Long"))
						{
							method.invoke(obj, rs.getLong(fieldName.toUpperCase()));
							break;
						}
						if (fieldType.equals("java.lang.String"))
						{
							method.invoke(obj, rs.getString(fieldName.toUpperCase()));
							break;
						}
						if (fieldType.equals("java.lang.Double"))
						{
							method.invoke(obj, rs.getDouble(fieldName.toUpperCase()));
							break;
						}
						if (fieldType.equals("java.lang.Integer"))
						{
							method.invoke(obj, rs.getInt(fieldName.toUpperCase()));
							break;
						}
						if (fieldType.equals("java.util.Date"))
						{
							method.invoke(obj, rs.getDate(fieldName.toUpperCase()));
							break;
						}
						if (fieldType.equals("java.math.BigDecimal"))
						{
							method.invoke(obj, rs.getBigDecimal(fieldName.toUpperCase()));
							break;
						}
						// 反射过程中各种异常捕获
					}
					catch (IllegalArgumentException e)
					{
						logger.debug(e.getMessage() + "参数异常");
					}
					catch (IllegalAccessException e)
					{
						logger.debug(e.getMessage() + "访问异常");
					}
					catch (InvocationTargetException e)
					{
						logger.debug(e.getMessage() + "方法绑定异常");
					}
					catch (SQLException e)
					{
						logger.debug(e.getMessage() + "sql异常");
					}
				}
			}
		}
		return obj;
	}


	/**
	 * @param clazz
	 *            bean类
	 * @param rs
	 *            结果集 (只有封装第一条结果)
	 * @return 封装了查询结果的bean对象
	 */
	public static Object getObj(Class clazz, ResultSet rs)
	{
		Field field = null;
		Object obj = null;
		try
		{
			// 取得ResultSet列名
			ResultSetMetaData rsmd = rs.getMetaData();
			// 获取记录集中的列数
			int counts = rsmd.getColumnCount();
			// 定义counts个String 变量
			String[] columnNames = new String[counts];
			// 给每个变量赋值(字段名称全部转换成小写)
			for (int i = 0; i < counts; i++)
			{
				columnNames[i] = rsmd.getColumnLabel(i + 1);//.toLowerCase();
			}
			// 变量ResultSet
			if (rs.next())
			{
				Object t = clazz.newInstance();
				// 反射, 从ResultSet绑定到JavaBean
				for (int i = 0; i < counts; i++)
				{
					String beanFieldName="";
					try
					{
						beanFieldName = getBeanFieldName(columnNames[i]);
						// 设置参数类型，此类型应该跟javaBean 里边的类型一样，而不是取数据库里边的类型
						field = clazz.getDeclaredField(beanFieldName);
					}
					catch(Exception e)
					{
						logger.info("bean没有属性"+beanFieldName);
						continue;
					}
					// 这里是获取bean属性的类型
					Class<?> beanType = field.getType();

					// 根据 rs 列名 ，组装javaBean里边的其中一个set方法，object 就是数据库第一行第一列的数据了
					//rs.getObject 不区分大小写
					Object value = rs.getObject(columnNames[i]);

					if (value != null)
					{

						// 这里是获取数据库字段的类型
						Class<?> dbType = value.getClass();

						// 处理日期类型不匹配问题
						if (dbType == java.sql.Timestamp.class && beanType == java.util.Date.class)
						{
							// value = new
							// java.util.Date(rs.getTimestamp(columnNames[i]).getTime());
							value = new java.util.Date(((java.sql.Timestamp) value).getTime());
						}
						// 处理double类型不匹配问题
						if (dbType == java.math.BigDecimal.class && beanType == double.class)
						{
							// value = rs.getDouble(columnNames[i]);
							value = new Double(value.toString());
						}
						// 处理int类型不匹配问题
						if (dbType == java.math.BigDecimal.class && beanType == int.class)
						{
							// value = rs.getInt(columnNames[i]);
							value = new Integer(value.toString());
						}
					}

					String setMethodName = getSetMethodName(columnNames[i]);
					// 第一个参数是传进去的方法名称，第二个参数是 传进去的类型；
					Method m = t.getClass().getMethod(setMethodName, beanType);
					if (m==null)
						logger.info("没有方法"+setMethodName);
					else
						// 第二个参数是传给set方法数据；如果是get方法可以不写
						m.invoke(t, value);

				}
				obj = t;
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
		return obj;
	}
	/**
	 * @param clazz
	 *            所要封装的javaBean
	 * @param rs
	 *            记录集
	 * @return ArrayList 数组里边装有 多个javaBean
	 * @throws Exception
	 * @说明：利用反射机制从ResultSet自动绑定到JavaBean；根据记录集自动调用javaBean里边的对应方法。
	 */
	public static List getList(Class clazz, ResultSet rs)
	{

		Field field = null;
		List lists = new ArrayList();

		try
		{
			// 取得ResultSet列名
			ResultSetMetaData rsmd = rs.getMetaData();
			// 获取记录集中的列数
			int counts = rsmd.getColumnCount();
			// 定义counts个String 变量
			String[] columnNames = new String[counts];
			// 给每个变量赋值(字段名称全部转换成小写)
			for (int i = 0; i < counts; i++)
			{
				columnNames[i] = rsmd.getColumnLabel(i + 1);//.toLowerCase();
			}
			// 变量ResultSet
			while (rs.next())
			{
				Object t = clazz.newInstance();
				// 反射, 从ResultSet绑定到JavaBean
				for (int i = 0; i < counts; i++)
				{

					String beanFieldName="";
					try
					{
						beanFieldName = getBeanFieldName(columnNames[i]);
						// 设置参数类型，此类型应该跟javaBean 里边的类型一样，而不是取数据库里边的类型
						field = clazz.getDeclaredField(beanFieldName);
					}
					catch(Exception e)
					{
						logger.info("bean没有属性"+beanFieldName);
						continue;
					}

					// 这里是获取bean属性的类型
					Class<?> beanType = field.getType();

					// 根据 rs 列名 ，组装javaBean里边的其中一个set方法，object 就是数据库第一行第一列的数据了
					
					Object value = rs.getObject(columnNames[i]);//

					if (value != null)
					{

						// 这里是获取数据库字段的类型
						Class<?> dbType = value.getClass();

						// 处理日期类型不匹配问题
						if (dbType == java.sql.Timestamp.class && beanType == java.util.Date.class)
						{
							// value = new
							// java.util.Date(rs.getTimestamp(columnNames[i]).getTime());
							value = new java.util.Date(((java.sql.Timestamp) value).getTime());
						}
						// 处理double类型不匹配问题
						if (dbType == java.math.BigDecimal.class && beanType == double.class)
						{
							// value = rs.getDouble(columnNames[i]);
							value = new Double(value.toString());
						}
						// 处理int类型不匹配问题
						if (dbType == java.math.BigDecimal.class && beanType == int.class)
						{
							// value = rs.getInt(columnNames[i]);
							value = new Integer(value.toString());
						}
					}

					String setMethodName = getSetMethodName(columnNames[i]);
					// 第一个参数是传进去的方法名称，第二个参数是 传进去的类型；
					Method m = t.getClass().getMethod(setMethodName, beanType);

					// 第二个参数是传给set方法数据；如果是get方法可以不写
					if (m==null)
						logger.info("没有方法"+setMethodName);
					else
						// 第二个参数是传给set方法数据；如果是get方法可以不写
						m.invoke(t, value);
				}
				lists.add(t);
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
		return lists;
	}
	
	//例如 BANK_CODE 转换成 bankCode setBankCode
	private static String getSetMethodName(String dbFieldName)
	{
		
		String [] fieldSplit = dbFieldName.split("_");
		String methodName="set";
		for(int i = 0;i<fieldSplit.length;i++)
		{
			methodName = methodName + fieldSplit[i].substring(0, 1).toUpperCase()+fieldSplit[i].substring(1).toLowerCase();
		}
		return methodName;
	}
	
	// 首写字母变大写 去掉下划线 下划线后第一个字母大写
	private static String getBeanFieldName(String dbFieldName)
	{
		String [] fieldSplit = dbFieldName.split("_");
		String beanFieldName="";
		for(int i = 0;i<fieldSplit.length;i++)
		{
			if (i==0)
				beanFieldName = beanFieldName + fieldSplit[i].toLowerCase();
			else
				beanFieldName = beanFieldName + fieldSplit[i].substring(0, 1).toUpperCase()+fieldSplit[i].substring(1).toLowerCase();
		}
		return beanFieldName;
	}
	
}
